﻿using System;
using System.Collections.Generic;

namespace NetTopologySuite.Index.Bintree
{
	public class Bintree<T>
	{
		public static Interval EnsureExtent(Interval itemInterval, double minExtent)
		{
			double num = itemInterval.Min;
			double num2 = itemInterval.Max;
			if (num != num2)
			{
				return itemInterval;
			}
			if (num == num2)
			{
				num -= minExtent / 2.0;
				num2 = num + minExtent / 2.0;
			}
			return new Interval(num, num2);
		}

		public Bintree()
		{
			this._root = new Root<T>();
		}

		public int Depth
		{
			get
			{
				if (this._root != null)
				{
					return this._root.Depth;
				}
				return 0;
			}
		}

		public int Count
		{
			get
			{
				if (this._root != null)
				{
					return this._root.Count;
				}
				return 0;
			}
		}

		public int NodeSize
		{
			get
			{
				if (this._root != null)
				{
					return this._root.NodeCount;
				}
				return 0;
			}
		}

		public void Insert(Interval itemInterval, T item)
		{
			this.CollectStats(itemInterval);
			Interval itemInterval2 = Bintree<T>.EnsureExtent(itemInterval, this._minExtent);
			this._root.Insert(itemInterval2, item);
		}

		public bool Remove(Interval itemInterval, T item)
		{
			Interval itemInterval2 = Bintree<T>.EnsureExtent(itemInterval, this._minExtent);
			return this._root.Remove(itemInterval2, item);
		}

		public IEnumerator<T> GetEnumerator()
		{
			IList<T> list = new List<T>();
			this._root.AddAllItems(list);
			return list.GetEnumerator();
		}

		public IList<T> Query(double x)
		{
			return this.Query(new Interval(x, x));
		}

		public IList<T> Query(Interval interval)
		{
			IList<T> list = new List<T>();
			this.Query(interval, list);
			return list;
		}

		public void Query(Interval interval, ICollection<T> foundItems)
		{
			this._root.AddAllItemsFromOverlapping(interval, foundItems);
		}

		private void CollectStats(Interval interval)
		{
			double width = interval.Width;
			if (width < this._minExtent && width > 0.0)
			{
				this._minExtent = width;
			}
		}

		private readonly Root<T> _root;

		private double _minExtent = 1.0;
	}
}
